package engine.net.datatype
{

	
	import engine.net.NetSocket;
	import engine.net.utils.NetDataType;
	import engine.net.utils.UnicodeCovert;
	
	import flash.geom.Point;
	import flash.utils.ByteArray;
	import flash.utils.Endian;

	//import publics.UnicodeCovert;
	/**
	 * ...
	 * @author sll
	 */
	public class ByteArrayEx extends ByteArray
	{
		public var charset:String = "utf-8";
		
		/**
		 * 向数据流中写入数组
		 * 
		 * @param data	：数据流
		 * @param vals	：数据数组
		 * 
		 */		
		public static function writeArray(data:ByteArrayEx,vals:Array):void
		{
			var tSize	:uint		=	vals.length;
			
			for(var i:uint = 0 ; i < tSize ; i ++)
			{
				if(vals[i] is int)
				{
					data.writeInt(vals[i]);
				}
				else if(vals[i] is Number)
				{
					data.writeFloat(vals[i]);
				}
				else if(vals[i] is String)
				{
					data.writeMultiByteEx(vals[i]);
				}
				else if(vals[i] is WString)
				{
					data.writeWString(vals[i]);
				}
				else if(vals[i] is Point)
				{
					data.writeObjectEx(vals[i]);
				}
			}
		}
		
		public function ByteArrayEx(byteEndian:String = "littleEndian") 
		{
			super();
			this.endian = byteEndian;		
		}
		
		public function setCharSet(cs:String):void
		{
			charset = cs;
		}		
		
		/**
		 * 获取服务器引擎类型VISTYPE_OBJECT(point类型)
		 * @param obj
		 * 
		 */
		public  function readObjectEx():Point
		{
			
			if (bytesAvailable < 8) 
			{
				throw Error("readObject byte len to short!");
			}
			
			var x:int = readInt();
			var y:int = readInt();
			return new Point(x, y);
		}

		/**
		 * 获取服务器引擎类型VISTYPE_LONGSTR(字符串)
		 * 注意 读属性时 不包含字符长度信息
		 * 读属性值时包含长度信息 
		 * @param bhavelenth
		 * @return 
		 * 
		 */		
		public function readMultiByteEx(bhavelenth:Boolean = false):String
		{
			var retStr:String = "";
			var char:String = "";
			if (bhavelenth)
			{
			   var length:int = readShort();
			}
			while (bytesAvailable > 0 )
			{
				char = readMultiByte(1, "gb2312");
				if (char == "") 
				{
					break;
				}
				retStr += char;
			}
			return retStr;
		}

		/**
		 * 获取服务器引擎类型VISTYPE_WIDESTR(宽字符串)
		 * @param charSet
		 * @return 
		 * 
		 */		
		public function readWString(charSet:String = "utf-8"):String
		{
			var retStr:String = "";
			var char:String = "";
			var length:int = readShort();
			while (bytesAvailable > 0 )
			{
				var byteArr:ByteArray = new ByteArray();
				var byte1:int = readByte() & 0xFF;
				var byte2:int = readByte() & 0xFF;
				byteArr.writeByte(byte1);
				byteArr.writeByte(byte2);
				byteArr.position = 0;
				var utf8:ByteArray = UnicodeCovert.Convert8(byteArr);
				char = utf8.readMultiByte(utf8.length, charSet);
				if (char == "")
				{
					break;
				}
				retStr += char;
			}
			return retStr;
		}
		
		/**
		 * 获取服务器引擎类型VISTYPE_WIDESTR(宽字符串)
		 * @param charSet
		 * @return 
		 * 
		 */		
		public function readWStringEx(charSet:String = "utf-8"):String
		{
			var retStr:String = "";
			var char:String = "";
//			var length:int = readShort();
			while (bytesAvailable > 0 )
			{
				var byteArr:ByteArray = new ByteArray();
				var byte1:int = readByte() & 0xFF;
				var byte2:int = readByte() & 0xFF;
				byteArr.writeByte(byte1);
				byteArr.writeByte(byte2);
				byteArr.position = 0;
				var utf8:ByteArray = UnicodeCovert.Convert8(byteArr);
				char = utf8.readMultiByte(utf8.length, charSet);
				if (char == "")
				{
					break;
				}
				retStr += char;
			}
			return retStr;
		}
		
		/**
		 * 获取服务器引擎类型(定长宽字符串)
		 * @param p_length
		 * @param charSet
		 * @return 
		 * 
		 */		
		public function readWStringByLength(p_length:Number,charSet:String = "utf-8"):String
		{
			var char:String = "";
			var isEnd:Boolean = false;
			
			for (var i:int = 0; i < p_length; i+=2) 
			{
				var byteArr:ByteArray = new ByteArray();
				var byte1:int = readByte() & 0xFF;
				var byte2:int = readByte() & 0xFF;
				
				if (!isEnd && byte1 == 0 && byte2 == 0){
					isEnd = true;
				}
				if (!isEnd){
					byteArr.writeByte(byte1);
					byteArr.writeByte(byte2);
					byteArr.position = 0;
					var utf8:ByteArray = UnicodeCovert.Convert8(byteArr);
					char += utf8.readMultiByte(utf8.length, charSet);
				}
			}
			
			return char;
		}

		
		//======================================================================================================
		
		/**
		 * 写入服务器引擎类型VISTYPE_OBJECT(point类型)
		 * @param obj
		 * 
		 */		
		public function writeObjectEx(obj:Point):void 
		{
			writeInt(obj.x);
			writeInt(obj.y);
		}
		
		/**
		 * 写入服务器引擎类型VISTYPE_LONGSTR(字符串)
		 * @param str
		 */		
		public function writeMultiByteEx(str:String):void
		{
			var tmp:ByteArray = new ByteArray();
			
			tmp.endian = this.endian;
			tmp.writeShort(getUTFStringByteLength(str) + 1);
			tmp.writeMultiByte(str, charset);
			//补零
			tmp.writeByte(0);
			
			this.writeBytes(tmp);
		}
		
		/**
		 * 写入服务器引擎类型VISTYPE_WIDESTR(宽字符串)
		 * @param srcStr
		 * 
		 */		
		public function writeWString(srcStr:String):void
		{
			var assem:ByteArray = new ByteArray();
			assem.endian = this.endian;
			
			var addlen:int = getUTFStringByteLength(srcStr)/srcStr.length * 2;
			assem.writeShort(srcStr.length * 2 + 2);
			var len:uint = 0;
			for (var i:int = 0; i < srcStr.length; i++) 
			{
				var str:String = srcStr.charAt(i);
				var unicode:ByteArray = UnicodeCovert.ConvertStr(str);
				assem.writeBytes(unicode);
			}
			var tmp:ByteArray = new ByteArray();
			tmp.length = 2;
			assem.writeBytes(tmp);
			
			this.writeBytes(assem);
		}
		
		/**
		 * 写入服务器引擎类型VISTYPE_WIDESTR(宽字符串)
		 * @param srcStr
		 * 
		 */		
		public function writeWStringEx(srcStr:String):void
		{
			var assem:ByteArray = new ByteArray();
			assem.endian = this.endian;
			
			var addlen:int = getUTFStringByteLength(srcStr)/srcStr.length * 2;
//			assem.writeShort(srcStr.length * 2 + 2);
			var len:uint = 0;
			for (var i:int = 0; i < srcStr.length; i++) 
			{
				var str:String = srcStr.charAt(i);
				var unicode:ByteArray = UnicodeCovert.ConvertStr(str);
				assem.writeBytes(unicode);
			}
			var tmp:ByteArray = new ByteArray();
			tmp.length = 2;
			assem.writeBytes(tmp);
			
			this.writeBytes(assem);
		}
		
		/**
		 * 自定义消息头 
		 * 
		 */		
		public function writeCustom():void
		{
			this.writeShort(12);
			//sn_bytearray.writeShort(SN_SocketMsgFlag.CLIENT_CUSTOMMSG_CHAT);
			var i:uint = 0;
			for (i = 0; i < 16; i++)
			{
				this.writeByte(0);
			}
			this.writeInt(NetSocket.serialNum);
			NetSocket.serialNum++;
			var point1:Point = new Point();
			point1.x = 0; 
			point1.y = 0;
			this.writeObjectEx(point1);
		}
		
		/**
		 * 向字节数组中写入一个字符串
		 *  
		 * @param str 待写入的字符串
		 * @param prefix 是否加前缀，前缀长度为8位 ，值为(字节长度+1)
		 * @param len 字符串长度，不为0时强制截断或补0
		 * 
		 */		
		public function writeStringEx(str:String, prefix:Boolean = false, len:int = 0) :void
		{
			var tmp:ByteArray = new ByteArray();
			tmp.endian = this.endian;
			tmp.writeMultiByte(str, charset);
			//补零
			tmp.writeByte(0);
			if (len != 0) 
			{
				tmp.length = len;
			}
			if (prefix)
			{
				this.writeShort(tmp.length);
			}
			this.writeBytes(tmp);
		}
		
		public function writeWidestrEx(srcStr:String, prefix:Boolean = false, fixedLen:uint = 0) :void
		{
			var assem:ByteArray = new ByteArray();
			assem.endian = this.endian;
			var len:uint = 0;
			for (var i:int = 0; i < srcStr.length; i++) 
			{
				var str:String = srcStr.charAt(i);
				var unicode:ByteArray = UnicodeCovert.ConvertStr(str);
				assem.writeBytes(unicode);
			}
			var tmp:ByteArray = new ByteArray();
			tmp.length = 2;
			assem.writeBytes(tmp);
			if (fixedLen != 0) 
			{
				assem.length = fixedLen;
			}
			if (prefix) 
			{
				this.writeShort(assem.length);
			}
			this.writeBytes(assem);
			
		}
		/**
		 * 根据type获取数据
		 * 注意 读属性时 不包含字符长度信息
		 * 读属性值时包含长度信息 
		 * @param bhavelenth
		 * @return 
		 * 
		 */	
		public function GetDataByType(type:uint,bhavelenth:Boolean = true):*
		{
			var data:* 		= null;
			switch (type)
			{
				case NetDataType.VISTYPE_BYTE:
				{					
					data = readByte();					
					break;
				}
				case NetDataType.VISTYPE_DWORD:
				{
					data = readInt();
					break;
				}
				case NetDataType.VISTYPE_WORD:
				{
					data = readUnsignedShort();				
					break;
				}
				case NetDataType.VISTYPE_FLOAT:
				{
					data = readFloat();										
					break;
				}
				case NetDataType.VISTYPE_LONGSTR:
				{
					data = readMultiByteEx(bhavelenth);
					break;
				}
				case NetDataType.VISTYPE_WIDESTR:
				{
					data = readWString();
					break;
				}
				case NetDataType.VISTYPE_OBJECT:
				{
					data = readObjectEx();					
					break;
				}
			}	
			return data;
		}	
		public function WriteData(data:Object):void
		{
			//			DATATYPE_INT		= 2,	// 整数(4 bytes)	
			//			DATATYPE_FLOAT		= 3,	// 浮点数(4 bytes)
			//			DATATYPE_STRING		= 4,	// 字符串长度(2 bytes)+字符串(以0结束)
			//			DATATYPE_WIDESTR	= 5,	// 字符串长度(2 bytes)+宽字符串(以0结束)
			//			DATATYPE_OBJECT		= 6,	// 对象标识符nIdent(4 bytes)+nSerial(4 bytes)
							
			if(data is int || data is uint)
			{
				writeByte(NetDataType.DATATYPE_INT);
				writeInt(int(data));
			}
			else if(data is Number)
			{
				writeByte(NetDataType.DATATYPE_FLOAT);
				writeFloat(Number(data));
			}
			else if(data is String)
			{
				writeByte(NetDataType.DATATYPE_STRING);
				writeMultiByteEx(String(data));
			}
			else if(data is WString)
			{
				writeByte(NetDataType.DATATYPE_WIDESTR);
				writeWString((data as WString).toStringEx());		
			}
			else if(data is Point)
			{
				writeByte(NetDataType.DATATYPE_OBJECT);
				writeObjectEx(data as Point);
			}			
		}	
		
		
		/**
		 * 获取UTF字符串字节长度
		 */
		private function getUTFStringByteLength(p_str:String):Number
		{
			var bt:ByteArray = new ByteArray();
			bt.endian = Endian.LITTLE_ENDIAN;
			
			bt.writeUTFBytes(p_str);
			
			return bt.length;
		}
	}
}